/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.rafkind.resrev.web.page;

import com.rafkind.resrev.dao.ReservationDao;
import com.rafkind.resrev.data.Reservation;
import com.rafkind.resrev.data.User;
import com.rafkind.resrev.service.MailService;
import com.rafkind.resrev.web.Authorized;
import com.rafkind.resrev.web.Session;
import com.rafkind.resrev.web.page.component.ApproveDenyReservationPanel;
import com.rafkind.resrev.web.page.component.EditOrDeleteReservationPanel;
import com.rafkind.resrev.web.page.component.FinalConditionPanel;
import com.rafkind.resrev.web.page.component.TitleMenu;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.DefaultDataTable;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.spring.injection.annot.SpringBean;

/**
 *
 * @author dave
 */
@Authorized
public class ReservationsPage extends WebPage {

  @SpringBean
  private ReservationDao reservationDao;
  
  @SpringBean
  private MailService mailService;
  
  public ReservationsPage() {
    add(new TitleMenu("titleMenu"));
    
    WebMarkupContainer approveContainer = 
        new WebMarkupContainer("approveContainer");
    
    List<IColumn<?>> approveColumns = new ArrayList<IColumn<?>>();
    
    final Stylist stylist = new Stylist.ForReservation();
    
    approveColumns.add(
        new ColorfulPropertyColumn(new Model<String>("Who"), "reserver.name", "reserver.name", stylist));
    
    approveColumns.add(
        new ColorfulPropertyColumn(new Model<String>("What"), "resource.name", "resource.name", stylist));
    
    approveColumns.add(
        new ColorfulPropertyColumn(new Model<String>("From"), "start", "start", stylist));
    
    approveColumns.add(
        new ColorfulPropertyColumn(new Model<String>("To"), "end", "end", stylist));
    
    approveColumns.add(new AbstractColumn<Reservation>(new Model<String>("Action")){
        public void populateItem(Item<ICellPopulator<Reservation>> cellItem, 
            String id, 
            IModel<Reservation> model) {

          cellItem.add(new ApproveDenyReservationPanel(id, model));
        }    
      });
    
    DefaultDataTable approveTable = new DefaultDataTable(
        "approveTable",
        approveColumns,
        new ApprovalDataProvider(),
        10);
    
    approveContainer.add(approveTable);
    User user = ((Session)getSession()).getCurrentUser();
    
    approveContainer.setVisible(
        reservationDao.countApprovableReservations(user) > 0);
    
    WebMarkupContainer pendingContainer = 
        new WebMarkupContainer("pendingContainer");
    
    List<IColumn<?>> pendingColumns = new ArrayList<IColumn<?>>();
    
    pendingColumns.add(
        new ColorfulPropertyColumn(new Model<String>("Who"), "reserver.name", "reserver.name", stylist));
    
    pendingColumns.add(
        new ColorfulPropertyColumn(new Model<String>("What"), "resource.name", "resource.name", stylist));
    
    pendingColumns.add(
        new ColorfulPropertyColumn(new Model<String>("From"), "start", "start", stylist));
    
    pendingColumns.add(
        new ColorfulPropertyColumn(new Model<String>("To"), "end", "end", stylist));
    
    pendingColumns.add(
        new AbstractColumn<Reservation>(new Model<String>("Authorization by")){
      public void populateItem(
          Item<ICellPopulator<Reservation>> cellItem, 
          String componentId, 
          IModel<Reservation> model) {
        
        Label label = null;
        String auth1 = null;
        String auth2 = null;
        
        Reservation reservation = model.getObject();
        if (reservation.getReserver() != null &&
            reservation.getReserver().getAuthorizor() != null)
          auth1 = reservation.getReserver().getAuthorizor().getName();

        if (reservation.getResource() != null &&
            reservation.getResource().getAuthorizor() != null)
          auth2 = reservation.getResource().getAuthorizor().getName();


        // aaah yeah, ternary operator bitches!
        label =
            new Label(
              componentId, 
              (auth1 == null 
                ?
                  (auth2 == null ? "" : auth2)
                :
                  (auth2 == null || auth1.equals(auth2) ? auth1 : auth1 + ", " + auth2)));

        label.add(new SimpleAttributeModifier(
          "style",
          stylist.getStyleFor(model.getObject())));
        
        cellItem.add(label);
      }
    });
    
    pendingColumns.add(new AbstractColumn<Reservation>(new Model<String>("Action")){
        public void populateItem(Item<ICellPopulator<Reservation>> cellItem, 
            String id, 
            IModel<Reservation> model) {

          cellItem.add(new EditOrDeleteReservationPanel(id, model));
        }    
      });
    
    DefaultDataTable pendingTable = new DefaultDataTable(
        "pendingTable",
        pendingColumns,
        new PendingDataProvider(),
        10);
    
    pendingContainer.add(pendingTable);
    pendingContainer.setVisible(
        reservationDao.countPendingReservations(user) > 0);
    
    add(approveContainer);
    add(pendingContainer);
    
    List<IColumn<?>> allColumns = new ArrayList<IColumn<?>>();
    
    allColumns.add(
        new ColorfulPropertyColumn(new Model<String>("Who"), "reserver.name", "reserver.name", stylist));
    
    allColumns.add(
        new ColorfulPropertyColumn(new Model<String>("What"), "resource.name", "resource.name", stylist));
    
    allColumns.add(
        new ColorfulPropertyColumn(new Model<String>("From"), "start", "start", stylist));
    
    allColumns.add(
        new ColorfulPropertyColumn(new Model<String>("To"), "end", "end", stylist));
    
    allColumns.add(
        new ColorfulPropertyColumn(new Model<String>("Authorized by"), "authorizor.name", "authorizor.name", stylist));
    
    allColumns.add(
        new AbstractColumn<Reservation>(new Model<String>("Status")){
      public void populateItem(
          Item<ICellPopulator<Reservation>> cellItem, 
          String componentId, 
          IModel<Reservation> model) {
        
        Label label = new Label(componentId, new PropertyModel(model, "authorization"));        
        
        if (model.getObject().getAuthorization() != null)
          label.add(new SimpleAttributeModifier("style", "color: " + 
              model.getObject().getAuthorization().getHexColor()));
        
        cellItem.add(label);
      }
    });
    
    allColumns.add(new AbstractColumn<Reservation>(new Model<String>("Initial Status")){
      public void populateItem(Item<ICellPopulator<Reservation>> cellItem, 
          String id, 
          IModel<Reservation> model) {

        cellItem.add(new Label(id, new PropertyModel(model, "beforeCondition"))
            .add(new SimpleAttributeModifier("style", "color: " 
            + (model.getObject().getBeforeCondition() != null ?
                model.getObject().getBeforeCondition().getHexColor()
                : "inherit") )));
      }

      @Override
      public String getSortProperty() {
        return "beforeCondition";
      }
      
      @Override
      public boolean isSortable() {
        return true;
      } 
    });
      
    allColumns.add(new AbstractColumn<Reservation>(new Model<String>("Final Status")){
      public void populateItem(Item<ICellPopulator<Reservation>> cellItem, 
          String id, 
          IModel<Reservation> model) {
        Reservation reservation = model.getObject();
        
        if (reservation.getAfterCondition() != null) {
          cellItem.add(new Label(id, new PropertyModel(model, "afterCondition"))
            .add(new SimpleAttributeModifier("style", "color: " 
            + (model.getObject().getAfterCondition() != null ?
                model.getObject().getAfterCondition().getHexColor()
                : "inherit") )));
        } else {
          // can set the final condition if:
          // you are the authorizor or
          // there is no authorizor and you are the reserver or
          // you are an admin
          
          // can't set if resource's condition has been updated already
          // (past end time of reservation)
          User user = ((Session)getSession()).getCurrentUser();
          boolean canSet = 
              user.equals(reservation.getAuthorizor()) ||
              (user.equals(reservation.getReserver()) 
                && reservation.getAuthorizor() == null) ||
              user.isAdmin();
          
          canSet &= (reservation.getEnd()
              .after(reservation.getResource().getLastConditionUpdate()));
          
          if (canSet) {
            cellItem.add(new FinalConditionPanel(id, model));
          } else {            
          }        
        }
      }
        
      @Override
      public String getSortProperty() {
        return "afterCondition";
      }
      
      @Override
      public boolean isSortable() {
        return true;
      }
    });
    
    
    
    DefaultDataTable allTable = new DefaultDataTable(
        "allTable",
        allColumns,
        new AllDataProvider(),
        10);
    
    add(allTable);
  }

  public MailService getMailService() {
    return mailService;
  }

  public ReservationDao getReservationDao() {
    return reservationDao;
  }
  
  public class ApprovalDataProvider 
      extends SortableDataProvider<Reservation> {
      
    public ApprovalDataProvider() {
      setSort("end", true);
    }
    
    public Iterator<? extends Reservation> iterator(int first, int count) {
      SortParam sp = getSort();
      User user = ((Session)getSession()).getCurrentUser();
      
      return getReservationDao()
          .getApprovableReservations(user, first, count, 
              sp.getProperty(), sp.isAscending()).iterator();
    }

    public IModel<Reservation> model(Reservation r) {
      return new DetachableReservationModel(getReservationDao(), r);
    }

    public int size() {
      User user = ((Session)getSession()).getCurrentUser();
      
      return getReservationDao().countApprovableReservations(user);
    }
    
  }
  
  public class PendingDataProvider 
      extends SortableDataProvider<Reservation> {

    public PendingDataProvider() {
      setSort("end", true);
    }
    
    public Iterator<? extends Reservation> iterator(int first, int count) {
      SortParam sp = getSort();
      User user = ((Session)getSession()).getCurrentUser();
      
      return getReservationDao()
          .getPendingReservations(user, first, count, 
              sp.getProperty(), sp.isAscending()).iterator();
    }

    public IModel<Reservation> model(Reservation r) {
      return new DetachableReservationModel(getReservationDao(), r);
    }

    public int size() {
      User user = ((Session)getSession()).getCurrentUser();
      
      return getReservationDao().countPendingReservations(user);
    }
    
  }
  
  public class AllDataProvider 
      extends SortableDataProvider<Reservation> {
      
    public AllDataProvider() {
      setSort("end", true);
    }
    
    public Iterator<? extends Reservation> iterator(int first, int count) {
      SortParam sp = getSort();
      User user = ((Session)getSession()).getCurrentUser();
      
      return getReservationDao()
          .getAllReservations(user, first, count, 
              sp.getProperty(), sp.isAscending()).iterator();
    }

    public IModel<Reservation> model(Reservation r) {
      return new DetachableReservationModel(getReservationDao(), r);
    }

    public int size() {
      User user = ((Session)getSession()).getCurrentUser();
      
      return getReservationDao().countAllReservations(user);
    }    
  }
  
  public static class DetachableReservationModel 
      extends LoadableDetachableModel<Reservation> {
    
    private int id;
    private ReservationDao reservationDao;
    
    public DetachableReservationModel(ReservationDao reservationDao, 
        Reservation reservation) {
      super(reservation);
      
      this.reservationDao = reservationDao;
      
      id = reservation.getId();
    }

    @Override
    public boolean equals(Object obj) {
      if (obj == null) {
        return false;
      }
      if (getClass() != obj.getClass()) {
        return false;
      }
      final DetachableReservationModel other = (DetachableReservationModel) obj;
      if (this.id != other.id) {
        return false;
      }
      return true;
    }

    @Override
    public int hashCode() {
      int hash = 3;
      hash = 53 * hash + this.id;
      return hash;
    }

    @Override
    protected Reservation load() {
      return reservationDao.getReservation(id);
    }
  }  
}